﻿#region 참조 네임스페이스

using System;
using System.ComponentModel;
using System.Net;
using System.Windows.Forms;
using Skying.ComponentModel;
using Skying.Net.NetworkInformation;
using Skying.Net.Sockets;
using Skying.Threading;

#endregion

namespace UdpClient
{
	public partial class MainForm : Form
	{
		#region 변수

		/// <summary>
		/// 서버와의 통신을 담당하는 클라이언트를 나타낸다.
		/// </summary>
		private Skying.Net.Sockets.UdpClient _client;

		/// <summary>
		/// 로깅을 위한 데이터 그리드 바인딩 리스트를 나타낸다.
		/// </summary>
		private SortableBindingList<Log> _logBindingList;

		/// <summary>
		/// 메시지를 반복적으로 전송하기 위한 동기화 타이머를 나타낸다.
		/// </summary>
		private SynchronizingTimer _sendRepeatedlyTimer;

		#endregion

		#region 생성자/소멸자

		public MainForm()
		{
			this.InitializeComponent();

			this._logBindingList = new SortableBindingList<Log>();

			this._sendRepeatedlyTimer = new SynchronizingTimer();

			this._client = new Skying.Net.Sockets.UdpClient(1024);

			this._client.Sent = (eventArgs) =>
			{
				TransferEventArgs result = eventArgs.Result;

				string logString = string.Empty;

				Header header = result.Header;

				switch (result.Header.PacketType)
				{
					case PacketType.Serialized:

						if (header.DataType.Equals(typeof(DateTime).FullName))
						{
							logString = string.Format("[S] - Serialized Object (Type: {0})", header.DataType);
						}

						break;

					case PacketType.Message:

						logString = "[S] - Message";

						break;

					case PacketType.File:

						break;
				}

				this.Log(logString);
			};

			this.LogDataGridView.DataSource = this._logBindingList;

			this.Load += (s, e) =>
			{
				IPAddress ipAddress;

				if (NetworkInformation.GetActiveIpAddress(out ipAddress))
				{
					this.IpAddressTextBox.Text = ipAddress.ToString();
				}
			};
		}

		#endregion

		#region 접속 정보

		/// <summary>
		/// 아이피 주소 텍스트 박스와 포트 번호 넘버릭 업다운 컨트롤로부터 서버 정보를 가져와 원격 주소 정보를 조합한다.
		/// </summary>
		/// <returns>원격 주소 정보가 반환된다.</returns>
		private IPEndPoint GetRemoteIpAddress()
		{
			IPEndPoint remoteEndPoint = null;

			try
			{
				IPAddress ipAddress;
				int portNumber;

				if (!IPAddress.TryParse(this.IpAddressTextBox.Text, out ipAddress))
				{
					return null;
				}

				portNumber = (int)this.PortNumericUpDown.Value;

				remoteEndPoint = new IPEndPoint(ipAddress, portNumber);
			}
			catch (Exception error)
			{

			}

			return remoteEndPoint;
		}

		#endregion

		#region 로깅

		/// <summary>
		/// 로그 그리드 뷰에 로그를 남긴다.
		/// </summary>
		/// <param name="logString">로그 문자열을 설정한다.</param>
		private void Log(string logString)
		{
			try
			{
				string nowString = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff");

				this._logBindingList.Add(new Log(nowString, logString));

				this.LogDataGridView.Sort(this.LogDataGridView.Columns[0], ListSortDirection.Descending);
			}
			catch (Exception error)
			{

			}
		}

		#endregion

		#region 반복 메시지 전송

		/// <summary>
		/// 반복 메시지 타이머를 시작한다.
		/// </summary>
		private void StartSendRepeatedlyTimer()
		{
			try
			{
				this._sendRepeatedlyTimer.Elapsed += () =>
				{
					this._client.SendMessageTo(this.GetRemoteIpAddress(), this.MessageTextBox.Text);
				};

				this._sendRepeatedlyTimer.SetPeriodic(new TimeSpan(0, 0, (int)this.RepeatSpanNumericUpDown.Value));
			}
			catch (Exception error)
			{

			}
		}

		/// <summary>
		/// 반복 메시지 타이머를 정지한다.
		/// </summary>
		private void StopSendRepeatedlyTimer()
		{
			try
			{
				this._sendRepeatedlyTimer.Cancel();
			}
			catch (Exception error)
			{

			}
		}

		#endregion

		#region 버튼 이벤트

		/// <summary>
		/// Send 버튼이 클릭된 경우 발생하는 이벤트를 구현한다.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void SendButton_Click(object sender, EventArgs e)
		{
			try
			{
				this._client.SendMessageTo(this.GetRemoteIpAddress(), this.MessageTextBox.Text);
			}
			catch (Exception error)
			{
				
			}
		}

		/// <summary>
		/// Send Repeatedly 버튼이 클릭됐을 때 발생하는 이벤트를 구현한다.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void SendRepeatedlyButton_Click(object sender, EventArgs e)
		{
			try
			{
				switch (this._sendRepeatedlyTimer.Enabled)
				{
					case true:

						this.StopSendRepeatedlyTimer();

						break;

					case false:

						this.StartSendRepeatedlyTimer();

						break;
				}
			}
			catch (Exception error)
			{

			}
		}

		#endregion
	}
}